#pragma once
#include <functional>
#include <unistd.h>
#include <strings.h>
#include "socket.hpp"

namespace TcpServer_ns
{
    using server_t = function<void(shared_ptr<socket_ns::TcpSocket> &, struct sockaddr_in &)>;

    class TcpServer; // 声明
    class ThreadData
    {
    public:
        ThreadData(shared_ptr<socket_ns::TcpSocket> &csk, struct sockaddr_in &skaddr, TcpServer *self)
            : _csk(csk), _skaddr(skaddr), _self(self)
        {
        }

        shared_ptr<socket_ns::TcpSocket> _csk;
        struct sockaddr_in _skaddr;
        TcpServer *_self;
    };

    class TcpServer
    {
    private:
        static void *pthreadserver(void *args)
        {
            ThreadData *td = static_cast<ThreadData *>(args);
            pthread_detach(pthread_self());
            td->_self->_commonserver(td->_csk, td->_skaddr);
            ::close(td->_csk->getsockfd()); // 防止文件描述符泄露
            delete td;
            return nullptr;
        }

    public:
        TcpServer(uint16_t port, server_t commonserver)
            : _listensocket(make_unique<socket_ns::TcpSocket>()), _isrunning(false), _commonserver(commonserver)
        {
            // 服务器一启动：1、创建套接字 2、绑定自己的网络地址 3、套接字设置为监听状态
            struct sockaddr_in localaddr;
            bzero(&localaddr, sizeof(localaddr));
            localaddr.sin_family = AF_INET;
            localaddr.sin_port = htons(port);
            localaddr.sin_addr.s_addr = INADDR_ANY;
            _listensocket->buildServerSocket((struct sockaddr *)&localaddr);
        }

        void start()
        {
            _isrunning = true;
            while (_isrunning)
            {
                // 1、连接用户
                struct sockaddr_in srcaddr;
                shared_ptr<socket_ns::TcpSocket> communicationsocket = _listensocket->Accept(&srcaddr);

                // 2、创建线程进行通信
                pthread_t tid;
                ThreadData *td = new ThreadData(communicationsocket, srcaddr, this);
                pthread_create(&tid, nullptr, pthreadserver, td);
            }
            _isrunning = false;
        }

        void stop()
        {
            _isrunning = false;
        }

        ~TcpServer()
        {
        }

    private:
        unique_ptr<socket_ns::Socket> _listensocket;
        bool _isrunning;
        server_t _commonserver;
    };
}